import json

from flask_restful import marshal


class Node(object):
    separator = '/'
    def __init__(self, parent=None, **kwargs):
        self.parent = parent
        self.__dict__.update(kwargs)
        self._dict.update(kwargs)


    @property
    def _dict(self):
        try:
            return self.__dict
        except AttributeError:
            self.__dict = {}
            return self.__dict

    @_dict.setter
    def _dict(self,val):
        self.__dict.update(val)


    @property
    def _children(self):
        try:
            return self.__children
        except AttributeError:
            self.__children = []
            return self.__children

    @property
    def children(self):

        return tuple(self._children)


    def __check_loop(self, node):
        if node is self:
            msg = "Cannot set parent. %r cannot be parent of itself."
            raise LookupError(msg % self)
        if self in node.path:
            msg = "Cannot set parent. %r is parent of %r."
            raise LookupError(msg % (self, node))

    def __detach(self, parent):
        if parent:
            self._pre_detach(parent)
            parentchildren = parent._children
            assert self in parentchildren, "Tree internal data is corrupt."
            parentchildren.remove(self)
            self._post_detach(parent)

    def __attach(self, parent):
        self._pre_attach(parent)
        parentchildren = parent._children
        assert self not in parentchildren, "Tree internal data is corrupt."
        parentchildren.append(self)
        self._post_attach(parent)

    def _pre_detach(self, parent):
        pass

    def _post_detach(self, parent):
        pass

    def _pre_attach(self, parent):
        """Method callx before attaching to `parent`."""
        pass

    def _post_attach(self, parent):
        pass

    @property
    def parent(self):
        try:
            return self._parent
        except AttributeError:
            return None

    @parent.setter
    def parent(self, value):
        try:
            parent = self._parent
        except AttributeError:
            parent = None
        if value is None:
            # make this node to root node
            self.__detach(parent)
        elif parent is not value:
            # change parent node
            self.__detach(parent)
            self.__check_loop(value)
            self.__attach(value)
        else:
            # keep parent
            pass
            # apply
        self._parent = value


    @property
    def path(self):
        return self._path

    @property
    def _path(self):
        path = []
        node = self
        while node:
            path.insert(0, node)
            node = node.parent
        return tuple(path)
    def __repr__(self):
        classname = self.__class__.__name__
        args = ["%r" % self.separator.join([""] + [str(node.name) for node in self.path])]
        for key, value in filter(lambda item: not item[0].startswith("_"),
                                 sorted(self.__dict__.items(),
                                        key=lambda item: item[0])):
            args.append("%s=%r" % (key, value))
        return "%s(%s)" % (classname, ", ".join(args))

    def to_json(self):
        sf = self.dict()
        return json.dumps(sf,ensure_ascii=False)

    def dict(self):
        json_object = dict(self._dict)
        children = [n.dict() for n in self.children]
        json_object['children'] = children

        return json_object


def page2dict(page, resource_fields):

    lic = [marshal(item,resource_fields)for item in page.items]
    rs = {'items':lic,
          'has_prev':page.has_prev,
          'has_next':page.has_next,
          'curr_page':page.page,
          'per_page':page.per_page,
          'total':page.total,
          }
    return rs



def gen_tree(paramList):

    lst=list(paramList)
    root = Node(name='root')
    nodes = []
    while lst:
        e = lst.pop(0)
        if e.parent_id is None or e.parent_id == 0:
            n = Node(parent=root, path=e.path, code=e.code, order=e.order, id=e.id,name=e.name)
            nodes.append(n)
        else:
            prepts =list(filter(lambda a:a.id == e.parent_id,nodes))
            if len(prepts)>0:
                parentNode = prepts[0]
                n = Node( parent=parentNode, path=e.path, code=e.code, order=e.order, id=e.id,name =e.name)
                nodes.append(n)
            else:
                lst.append(e)
    return root
